package com.hmsm.sys.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class LocalDept<T extends LocalDept<T, U>, U extends LocalUser> {

	private static final Log log = LogFactory.getLog(LocalDept.class);
	
	private Integer deptType;

	public Integer getDeptType() {
		return deptType;
	}

	public void setDeptType(Integer deptType) {
		this.deptType = deptType;
	}
	
	public DeptTypeEnum getDeptTypeEnum(){
		DeptTypeEnum neptTypeEnum = null;
		
		if (deptType!=null){
			neptTypeEnum = DeptTypeEnum.valueOf(deptType);
		}
		
		return neptTypeEnum;
	}
	
	public void setDeptTypeEnum(DeptTypeEnum deptTypeEnum){
		deptType = deptTypeEnum.value();
	}
	
	private String relevanceConfig;

	public String getRelevanceConfig() {
		return relevanceConfig;
	}

	public void setRelevanceConfig(String relevanceConfig) {
		this.relevanceConfig = relevanceConfig;
	}

	public String getRelevanceType() {
		String relevanceType = RelevanceConfig.getRelevanceType(relevanceConfig);
		return relevanceType;
	}
	
	public boolean isSyncNeed(){
		boolean syncNeed = !"".equals(getRelevanceType());
		
		return syncNeed;
	}

	private Object bindDepart;
	
	public Object getBindDepart() {
		return bindDepart;
	}

	public void setBindDepart(Object bindDepart) {
		this.bindDepart = bindDepart;
	}

	public void bind(RTXDeptBean bindDepart) {
		this.bindDepart = bindDepart;
	}

	private Map<String, List<? extends Object>> refObjectListMap;
	
	public Map<String, List<? extends Object>> getRefObjectListMap() {
		return refObjectListMap;
	}

	public void setRefObjectListMap(
			Map<String, List<? extends Object>> refObjectListMap) {
		this.refObjectListMap = refObjectListMap;
	}
	
	private Map<Integer, T> deptMap;
	
	public Map<Integer, T> getDeptMap() {
		return deptMap;
	}

	public void setDeptMap(Map<Integer, T> deptMap) {
		this.deptMap = deptMap;
	}

	private Map<Integer, U> userMap;

	public Map<Integer, U> getUserMap() {
		return userMap;
	}

	public void setUserMap(Map<Integer, U> userMap) {
		this.userMap = userMap;
	}

	private Map<Serializable, U> userRelevanceMap;

	public Map<Serializable, U> getUserRelevanceMap() {
		return userRelevanceMap;
	}

	private Map<String, Set<Integer>> userLoginNameMap;
	
	public Map<String, Set<Integer>> getUserLoginNameMap() {
		return userLoginNameMap;
	}

	public void setUserLoginNameMap(Map<String, Set<Integer>> userLoginNameMap) {
		this.userLoginNameMap = userLoginNameMap;
	}

	private Map<String, List<U>> userNameMap;
    
    // Constructors

	public Map<String, List<U>> getUserNameMap() {
		return userNameMap;
	}

	public void setUserNameMap(Map<String, List<U>> userNameMap) {
		this.userNameMap = userNameMap;
	}

	public boolean isOrganization(){
		boolean result = false;
		
		if (DeptTypeEnum.ORG.equals(getDeptTypeEnum())){
			result = true;
		}
		
		return result;
	}

	/**
	 * 在组织机构用户中按姓名及登录名查找指定用户
	 * @param name
	 * @param userName
	 * @return
	 */
	public U getUser(String name, String userName) {
		U findedUser = null;
		
		if (userNameMap==null) {
			initUserNameMap();
		}
		
		if (userNameMap.containsKey(name)){
			List<U> list = userNameMap.get(name);
			if (list.size()==1){
				findedUser = list.get(0);
			} else {
				for (U user:list){
					if (user.getUserName().equals(userName)){
						findedUser = user;
						break;
					} else {
						
					}
				}
			}
		}
		
		return findedUser;
	}
	
	// Property accessors
	
	// Fields

	/**
	 * 到指定组织机构的路径
	 * @param parent
	 * @return
	 */
	public String getPath(T parent){
		String path = "";
		List<T> list = getParentList(); 
		for (int i=list.size()-1;i>=0;i--){
			T p = list.get(i); 
			if (p.equals(parent)){
				break;
			}
			if(p.getDeptTypeEnum()!=DeptTypeEnum.GROUP){
				path = p.getName() + "\\" + path;
			}
		}
		
		return path;
	}
	
	public abstract T getParent();
	
	public abstract List<T> getSubDepts();
	
	public abstract void setSubDepts(List<T> subDepts);
	
	public abstract List<T> getAllDepts();
	
	public abstract List<U> getAllUsers();

	public void bind(Object bindDepart) {
		this.bindDepart = bindDepart;
	}
	
	protected void initUserNameMap(){

		userNameMap = new HashMap<String, List<U>>();
		List<U> allUsers = getAllUsers();
		for (U userInfo : allUsers) {
			List<U> list;
			if (userInfo==null){
				log.error("有问题呢！");
			}else{
				if(userNameMap.containsKey(userInfo.getName())){
					list = userNameMap.get(userInfo.getName());
				}else{
					list = new ArrayList<U>();
					userNameMap.put(userInfo.getName(), list);
				}
				list.add(userInfo);
				
			}
		}
	}

	/**
	 * 获取指定名称或别名的部门，如果下级机构是部门，则在所有下级机构中查找，否则仅在直属下级机构中查找
	 * @param deptName
	 * @return
	 */
	public T getSubDepartByName(String deptName) {
		T findedDepart = null;
		
		List<T> list;
		if (isOrganization()){
			list = getAllDepts();
		} else {
			list = getSubDepts();
		}
		
		// 匹配所有下级部门
		for (T depart:list){
			if (depart.getName().equals(deptName)||depart.getAliasName().equals(deptName)){
				findedDepart = depart;
				break;
			}
		}
				
		return findedDepart;
	}
	
	public abstract String getAliasName();

	public List<T> getParentList(){
		List<T> list = new ArrayList<T>();
		
		if (getParent()!=null){
			for (T p:getParent().getParentList()){
				list.add(p);
			}
			list.add(getParent());
		}
		
		return list;
	}

	// 在未匹配的部门中按关联id查找部门，如找不到，再分别在上级、平级和下级部门中查找
	public T getSubDepartByRelevanceId(Long relevanceId) {
		T findedDepart = null;
				
		// 匹配所有下级部门
		for (T depart:getSubDepts()){
			if (depart.getBindDepart()==null&&depart.getIdType()!=null&&depart.getIdType().intValue()==relevanceId.intValue()){
				findedDepart = depart;
				break;
			}
		}
		if (findedDepart==null&&getParent()!=null){
			for(T depart:getParent().getSubDepts()){
				if (!depart.equals(this)){
					if (depart.getBindDepart()==null&&depart.getIdType()!=null&&depart.getIdType().intValue()==relevanceId.intValue()){
						findedDepart = depart;
						break;
					}
					for(T subDept:depart.getSubDepts()){
						if (subDept.getBindDepart()==null&&subDept.getIdType()!=null&&subDept.getIdType().intValue()==relevanceId.intValue()){
							findedDepart = subDept;
							break;
						}
					}
					if (findedDepart!=null){
						break;
					}
				}
			}
		}
		if (findedDepart==null){
			for (T depart:getSubDepts()){
				for(T subDept:depart.getSubDepts()){
					if (subDept.getBindDepart()==null&&subDept.getIdType()!=null&&subDept.getIdType().intValue()==relevanceId.intValue()){
						findedDepart = subDept;
						break;
					}
				}
				if (findedDepart!=null){
					break;
				}
			}
		}
				
		return findedDepart;
	}

	public abstract Integer getIdType();

	public U getUserByRelevanceId(Serializable relevanceId) {
		U findedUser = null;
		
		// 获取同步配置根部门
		T relevanceRootDept = (T)this;
		if (getParent()!=null){
			for(T parentDept: getParentList()){
				if (!"".equals(parentDept.getRelevanceType())){
					relevanceRootDept = parentDept;
				}
			}
		}
		
		try {
			if (relevanceRootDept.getUserRelevanceMap().containsKey(relevanceId)){
				findedUser = relevanceRootDept.getUserRelevanceMap().get(relevanceId);
				if(findedUser!=null&&findedUser.getBindUser()!=null){
					findedUser = null;
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return findedUser;
	}

	/**
	 * 初始化用户关联表
	 * @param allLocalUsers
	 */
	public void initUserRelevanceMap(Collection<U> allLocalUsers) {
		
		/**
		 * 用户关联表初始化
		 */
		if (userRelevanceMap==null){
			userRelevanceMap = new HashMap<Serializable, U>();
			for(U user: allLocalUsers){
				if(user.getIdType()!=null){
					String id = user.getIdType();
					if (!userRelevanceMap.containsKey(id)){
						userRelevanceMap.put(id, user);
					}
				}
			}
		}
		
	}
	
	/**
	 * 初始化本地用户表
	 * @param allLocalUsers
	 */
	public void initLocalUserMap(List<U> allLocalUsers) {
		
		/**
		 * 用户表初始化
		 */
		if (userMap==null){
			userMap = new HashMap<Integer, U>();
			for(U user: allLocalUsers){
				if(user.getPkId()!=null&&user.getPkId()!=0){
					if (!userMap.containsKey(user.getPkId())){
						userMap.put(user.getPkId(), user);
					}
				}
			}
		}
		
		/**
		 * 登录名表初始化
		 */
		if(userLoginNameMap==null){
			userLoginNameMap = new HashMap<String, Set<Integer>>();
			
			for(U localUser: allLocalUsers){
				dupUserCheck(localUser);
			}
		}

	}

	public void dupUserCheck(U localUser) {
		if (!userMap.containsKey(localUser.getPkId())){
			userMap.put(localUser.getPkId(), localUser);
		}
		Set<Integer> userIds;
		if (userLoginNameMap.containsKey(localUser.getUserName())){
			userIds = userLoginNameMap.get(localUser.getUserName());
		}else{
			userIds = new HashSet<Integer>();
			userLoginNameMap.put(localUser.getUserName(), userIds);
		}
		if (!userIds.contains(localUser.getPkId())){
			userIds.add(localUser.getPkId());
		}
	}
	
	/**
	 * 获取部门路径名称
	 * @param model 模式 0-不含组织机构名，1-含组织机构名，2-根部门用组织机构名
	 * @return
	 */
	public String getDeptPathName(int model) {
		return getDeptPathName(model, null);
	}
	
	/**
	 * 获取部门路径名称
	 * @param model 模式 0-不含组织机构名，1-含组织机构名，2-根部门用组织机构名
	 * @return
	 */
	public String getDeptPathName(int model, LocalDept parent) {
		String userDept = "";
		if(!isOrganization()||model!=0||isOrganization()&&model==2){
			if(isOrganization()){
				userDept += "["+getName()+"]";
			}else{
				userDept += getName();
			}
		}
		if(!isOrganization()){
			List<T> parentList = getParentList();
			for(int i = parentList.size()-1;i>=0;i--) {
				T deptInfo = parentList.get(i);
				if (deptInfo.equals(parent)){
					break;
				}
				
				if(deptInfo.getPkId()==null||deptInfo.getPkId()==0){
					break;
				}
				
				if(deptInfo.getDeptType()==null||deptInfo.getDeptType()!=DeptTypeEnum.GROUP.value()&&(model==1||(parent==null||!deptInfo.equals(parent))||!deptInfo.isOrganization())){
					if(deptInfo.isOrganization()){
						userDept = "["+deptInfo.getName()+"]" + ">" + userDept;
					}else{
						userDept = deptInfo.getName() + ">" + userDept;
					}
				}
				
				if(deptInfo.isOrganization()){
					break;
				}
			}
		}
		return userDept;
	}

	public abstract Integer getPkId();

	public abstract void setPkId(Integer pkId);

	public abstract Integer getParId();

	public abstract void setParId(Integer pkId);

	public abstract String getName();

	public abstract void setName(String name);

	public abstract List<U> getUsers();

	public abstract void setUsers(List<U> users);

	public abstract Integer getLevel();

	public abstract int getRealLevel();

	public abstract void setIdType(Integer intValue);

	public abstract void setParent(T bindDept);

	public abstract void setLevel(Integer level);

	public abstract Integer getOrgId();

	public abstract void setOrgId(Integer orgId);

	public abstract T getOrgRootDept();
	
}
